package cn.edu.sjtu.stap.cfg.builder;

import java.util.*;

import org.aspectj.org.eclipse.jdt.internal.compiler.ast.*;

import cn.edu.sjtu.stap.cfg.ControlFlowGraph;
import cn.edu.sjtu.stap.cg.CallGraph;

/**
 * The default CFG builder. It implements the construction for intra-module and
 * inter-module CFGs. It builds intra-module CFGs for one file and another, in
 * the form of <code>CompilationUnitDeclaration</code>. Then, it builds
 * inter-module CFGs for all the intra-module CFGs with the help of Call Graphs.
 * As a result, the order of CFG construction should be as follows:
 * 
 * <pre>
 *     ICfgBuilder builder = DefaultCfgBuilder.getInstance();
 *     
 *     CompilationUnitDeclaration[] units;
 *     // Fetch the units.
 *     foreach (CompilationUnitDeclaration unit : units) {
 *         builder.buildIntraModuleCfg(unit);
 *     }
 *     
 *     // Construct Call Graphs and put the result into &quot;cgs&quot;.
 *     // Fetch program entries where each of the inter-module CFGs starts and put them into &quot;entries&quot;.
 *     builder.buildInterModuleCfg(cgs, builder.getIntraModuleCfgs(), entries);
 * </pre>
 * 
 * @author William
 * 
 */
public class DefaultCfgBuilder implements ICfgBuilder {
    /**
     * Inplementation for intra-module CFG construction.
     */
    private IntraModuleCfgBuilder intraBuilder = new IntraModuleCfgBuilder();

    /**
     * Implementation for inter-module CFG construction.
     */
    private InterModuleCfgBuilder interBuilder = new InterModuleCfgBuilder();

    /**
     * Singleton instance.
     */
    private static DefaultCfgBuilder instance = null;

    /**
     * Default constructor.
     * 
     */
    public DefaultCfgBuilder() {
        // Empty.
    }

    /**
     * Get an instance of the default CFG builder. The singleton instance is
     * returned by default.
     * 
     * @return ICfgBuilder an instance of the default CFG builder.
     */
    public static ICfgBuilder getInstance() {
        if (instance == null) {
            instance = new DefaultCfgBuilder();
        }
        return instance;
    }

    /*
     * (non-Javadoc)
     * 
     * @see cn.edu.sjtu.stap.cfg.builder.ICfgBuilder#initialize()
     */
    public void initialize() {
        intraBuilder.initialize();
        interBuilder.initialize();
    }

    /*
     * (non-Javadoc)
     * 
     * @see cn.edu.sjtu.stap.cfg.builder.ICfgBuilder#buildIntraModuleCfg(org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration)
     */
    public void buildIntraModuleCfg(CompilationUnitDeclaration unit) {
        unit.traverse(intraBuilder, unit.scope);
    }

    /*
     * (non-Javadoc)
     * 
     * @see cn.edu.sjtu.stap.cfg.builder.ICfgBuilder#getIntraModuleCfgs()
     */
    public Map<AbstractMethodDeclaration, ControlFlowGraph> getIntraModuleCfgs() {
        return intraBuilder.getResult();
    }

    /*
     * (non-Javadoc)
     * 
     * @see cn.edu.sjtu.stap.cfg.builder.ICfgBuilder#buildInterModuleCfg(java.util.Map,
     *      java.util.Map, java.util.Set)
     */
    public void buildInterModuleCfg(Map<AbstractMethodDeclaration, CallGraph> cgs,
            Map<AbstractMethodDeclaration, ControlFlowGraph> cfgs, Set<AbstractMethodDeclaration> entries) {
        Iterator<AbstractMethodDeclaration> i = entries.iterator();
        while (i.hasNext()) {
            AbstractMethodDeclaration m = i.next();
            CallGraph cg = cgs.get(m);
            if (null == cg) {
                return;
            } else {
                cg = CallGraph.getSubCallGraph(cg.getRoot());
            }
            interBuilder.buildInterModuleCfg(cg, cfgs, m);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see cn.edu.sjtu.stap.cfg.builder.ICfgBuilder#getInterModuleCfgs()
     */
    public Map<AbstractMethodDeclaration, ControlFlowGraph> getInterModuleCfgs() {
        return interBuilder.getResult();
    }
}
